package com.yzt.zhuju.widget.tuiview.crop;

import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Build;
import android.view.MotionEvent;

import androidx.annotation.ColorInt;
import androidx.annotation.Px;
import androidx.annotation.StyleableRes;

import com.yzt.zhuju.widget.tuiview.SelectorFactory;

import java.util.Arrays;

/**
 * <pre>
 *     author : amin
 *     time   : 2018/5/24
 *     desc   :
 * </pre>
 */
public class CropLayoutHelper {
    private final Builder mBuilder;

    private final Path mCropPath;
    private final Paint mPaint;
    private final Region mAreaRegion;
    private RectF mLayer;

    private CropLayoutHelper(Builder builder) {
        this.mBuilder = builder;
        mCropPath = new Path();
        mAreaRegion = new Region();
        mPaint = new Paint();
        mPaint.setColor(Color.WHITE);
        mPaint.setDither(true);
        mPaint.setAntiAlias(true);
    }

    public void onSizeChanged(int w, int h) {
        mLayer = new RectF(0, 0, w, h);
        mCropPath.reset();
        if (mBuilder.asCircle) {
            mCropPath.addCircle(w >> 1, h >> 1, Math.min(w, h) / 2, Path.Direction.CW);
            //空操作,使Path区域占满画布
            mCropPath.moveTo(-1, -1);
            mCropPath.moveTo(w + 1, h + 1);
        } else {
            mCropPath.addRoundRect(new RectF(0, 0, w, h), mBuilder.radius, Path.Direction.CW);
        }
        mAreaRegion.setPath(mCropPath, new Region(0, 0, w, h));
    }

    public void beforeDispatchDraw(Canvas canvas) {
        canvas.saveLayer(mLayer, null, Canvas.ALL_SAVE_FLAG);
    }

    public void afterDispatchDraw(Canvas canvas) {
        if (mBuilder.strokeWidth > 0) {
            // 支持半透明描边
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
            mPaint.setColor(Color.WHITE);
            mPaint.setStrokeWidth(mBuilder.strokeWidth * 2);
            mPaint.setStyle(Paint.Style.STROKE);
            canvas.drawPath(mCropPath, mPaint);

            // 绘制描边
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
            mPaint.setColor(mBuilder.strokeColor);
            mPaint.setStyle(Paint.Style.STROKE);
            canvas.drawPath(mCropPath, mPaint);
        }

        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.FILL);

        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
            canvas.drawPath(mCropPath, mPaint);
        } else {
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
            final Path path = new Path();
            if (mLayer != null) {
                path.addRect(0, 0, (int) mLayer.width(), (int) mLayer.height(), Path.Direction.CW);
                path.op(mCropPath, Path.Op.DIFFERENCE);
                canvas.drawPath(path, mPaint);
            }
        }
        canvas.restore();
        /*if (mBuilder.strokeWidth > 0) {
            mPaint.setStrokeWidth(mBuilder.strokeWidth * 2);
            mPaint.setStyle(Paint.Style.STROKE);
            if (mBuilder.strokeAbove) {
                mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
                mPaint.setColor(mBuilder.strokeColor);
                mPaint.setStyle(Paint.Style.STROKE);
                canvas.drawPath(mCropPath, mPaint);
            } else {
                //裁减掉Stroke的内容
                mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
                mPaint.setColor(Color.WHITE);
                canvas.drawPath(mCropPath, mPaint);
                // 绘制描边
                mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
                mPaint.setColor(mBuilder.strokeColor);
                canvas.drawPath(mCropPath, mPaint);
            }
        }
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawPath(mCropPath, mPaint);
        canvas.restore();*/
    }

    public boolean processTouchEvent(MotionEvent ev) {
        //在区域中才响应事件
        return mAreaRegion.contains((int) ev.getX(), (int) ev.getY());
    }

    public CropLayoutHelper asCircle(boolean asCircle) {
        this.mBuilder.asCircle = asCircle;
        return this;
    }

    public CropLayoutHelper corner(@Px int corner) {
        Arrays.fill(mBuilder.radius, corner);
        return this;
    }

    public CropLayoutHelper topLeftCorner(@Px int topLeftCorner) {
        mBuilder.radius[0] = mBuilder.radius[1] = topLeftCorner;
        return this;
    }

    public CropLayoutHelper topRightCorner(@Px int topRightCorner) {
        mBuilder.radius[2] = mBuilder.radius[3] = topRightCorner;
        return this;
    }

    public CropLayoutHelper bottomRightCorner(@Px int bottomRightCorner) {
        mBuilder.radius[4] = mBuilder.radius[5] = bottomRightCorner;
        return this;
    }

    public CropLayoutHelper bottomLeftCorner(@Px int bottomLeftCorner) {
        mBuilder.radius[6] = mBuilder.radius[7] = bottomLeftCorner;
        return this;
    }

    public CropLayoutHelper strokeWidth(@Px int strokeWidth) {
        this.mBuilder.strokeWidth = strokeWidth;
        return this;
    }

    public CropLayoutHelper strokeColor(@ColorInt int strokeColor) {
        this.mBuilder.strokeColor = strokeColor;
        return this;
    }

    public CropLayoutHelper strokeAbove(boolean strokeAbove) {
        this.mBuilder.strokeAbove = strokeAbove;
        return this;
    }

    public void updateView() {
        mBuilder.cropView.updateView();
    }

    public static final class Builder {
        private final TypedArray typedArray;
        private final ICropView cropView;
        private boolean asCircle = false;
        private final float[] radius = new float[8];
        private int strokeWidth = 0;
        private int strokeColor = SelectorFactory.INVALID;
        private boolean strokeAbove = false;

        public Builder(ICropView cropView, TypedArray typedArray) {
            this.cropView = cropView;
            this.typedArray = typedArray;
        }

        public Builder asCircle(@StyleableRes int asCircle) {
            this.asCircle = typedArray.getBoolean(asCircle, false);
            return this;
        }

        public Builder corner(@StyleableRes int corner) {
            Arrays.fill(radius, typedArray.getDimensionPixelOffset(corner, 0));
            return this;
        }

        public Builder topLeftCorner(@StyleableRes int topLeftCorner) {
            int dimen = typedArray.getDimensionPixelOffset(topLeftCorner, -1);
            if (dimen != -1) {
                radius[0] = radius[1] = dimen;
            }
            return this;
        }

        public Builder topRightCorner(@StyleableRes int topRightCorner) {
            int dimen = typedArray.getDimensionPixelOffset(topRightCorner, -1);
            if (dimen != -1) {
                radius[2] = radius[3] = dimen;
            }
            return this;
        }

        public Builder bottomRightCorner(@StyleableRes int bottomRightCorner) {
            int dimen = typedArray.getDimensionPixelOffset(bottomRightCorner, -1);
            if (dimen != -1) {
                radius[4] = radius[5] = dimen;
            }
            return this;
        }

        public Builder bottomLeftCorner(@StyleableRes int bottomLeftCorner) {
            int dimen = typedArray.getDimensionPixelOffset(bottomLeftCorner, -1);
            if (dimen != -1) {
                radius[6] = radius[7] = dimen;
            }
            return this;
        }

        public Builder strokeWidth(@StyleableRes int strokeWidth) {
            this.strokeWidth = typedArray.getDimensionPixelOffset(strokeWidth, 0);
            return this;
        }

        public Builder strokeColor(@StyleableRes int strokeColor) {
            this.strokeColor = typedArray.getColor(strokeColor, SelectorFactory.INVALID);
            return this;
        }

        public Builder strokeAbove(@StyleableRes int strokeAbove) {
            this.strokeAbove = typedArray.getBoolean(strokeAbove, false);
            return this;
        }

        public CropLayoutHelper build() {
            return new CropLayoutHelper(this);
        }
    }
}
